package br.unifacs.mda.plugin.code.generator.impl;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import psmjava.JavaPackage;
import psmjava.JavaType;
import psmjava.impl.JavaClassImpl;
import psmjava.impl.JavaEnumerationImpl;
import psmjava.impl.JavaInterfaceImpl;
import psmjava.impl.JavaPackageImpl;
import br.unifacs.mda.plugin.code.generator.CodeGeneratorIF;
import br.unifacs.mda.plugin.util.GeneratorUtility;

/**
 * 
 * @author George Pacheco
 */
public class CodeGenerator implements CodeGeneratorIF {

	/* ---------- Attributes ---------- */

	private final static String TEMPLATE_CLASS = "/templates/Class.vm";

	private final static String TEMPLATE_INTERFACE = "/templates/Interface.vm";

	private final static String TEMPLATE_ENUMERATION = "/templates/Enumeration.vm";

	private String projectName;

	private final static String PATH = "C:/Teste/";

	private GeneratorUtility util;

	/* ---------- Associations ---------- */

	/* ---------- Constructors ---------- */

	/** Creates a new instance of GenerationPim */
	public CodeGenerator(String projectName) {
		this.projectName = projectName;
	}

	/* ---------- Gets and Setters ---------- */

	/* ---------- Public Methods ---------- */

	@Override
	public void init() throws Exception {

		Properties p = new Properties();
		p.setProperty("resource.loader", "class");
		p.setProperty("class.resource.loader.description",
				"Velocity Classpath Resource Loader");
		p
				.setProperty("class.resource.loader.class",
						"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
		Velocity.init(p);
		util = new GeneratorUtility();
	}

	@Override
	public void startPackage(List<JavaPackageImpl> packages) throws Exception {
		for (JavaPackageImpl pack : packages) {
			this.createPackage(this.projectName, pack);
		}
	}

	public void createPackage(String pathname, JavaPackage pack) {
		new File(pathname, pack.getName()).mkdirs();
		if (pack.getNestedPackage().size() > 0) {
			for (JavaPackage p : pack.getNestedPackage()) {
				this.createPackage(pathname + "/" + pack.getName(), p);
			}
		}
	}

	@Override
	public void startClass(List<JavaClassImpl> classes) throws Exception {
		for (JavaClassImpl c : classes) {
			this.createClass(c);
		}
	}

	@Override
	public void startInterface(List<JavaInterfaceImpl> interfaces)
			throws Exception {
		for (JavaInterfaceImpl i : interfaces) {
			this.createInterface(i);
		}
	}

	@Override
	public void starEnumeration(List<JavaEnumerationImpl> enumerations)
			throws Exception {
		for (JavaEnumerationImpl e : enumerations) {
			this.createEnumeration(e);
		}
	}

	/* ---------- Private Methods ---------- */

	private void createClass(JavaClassImpl _class) throws Exception {
		VelocityContext context = new VelocityContext();
		Template template = Velocity.getTemplate(TEMPLATE_CLASS);

		context.put("packages", this.getPackages(_class).get(0));
		context.put("class", _class);
		context.put("util", util);
		BufferedWriter writer = new BufferedWriter(new FileWriter(
				this.projectName + "/" + this.getPackages(_class).get(1) + "/"
						+ _class.getName() + ".java"));

		template.merge(context, writer);
		writer.flush();
		writer.close();
	}

	private void createInterface(JavaInterfaceImpl _interface) throws Exception {
		VelocityContext context = new VelocityContext();
		Template template = Velocity.getTemplate(TEMPLATE_INTERFACE);

		context.put("packages", this.getPackages(_interface).get(0));
		context.put("interface", _interface);
		context.put("util", util);
		BufferedWriter writer = new BufferedWriter(new FileWriter(
				this.projectName + "/" + this.getPackages(_interface).get(1)
						+ "/" + _interface.getName() + ".java"));

		template.merge(context, writer);
		writer.flush();
		writer.close();
	}

	private void createEnumeration(JavaEnumerationImpl enumeration)
			throws Exception {
		VelocityContext context = new VelocityContext();
		Template template = Velocity.getTemplate(TEMPLATE_ENUMERATION);

		context.put("packages", this.getPackages(enumeration).get(0));
		context.put("enumeration", enumeration);
		context.put("util", util);
		BufferedWriter writer = new BufferedWriter(new FileWriter(
				this.projectName + "/" + this.getPackages(enumeration).get(1)
						+ "/" + enumeration.getName() + ".java"));

		template.merge(context, writer);
		writer.flush();
		writer.close();
	}

	private ArrayList<String> getPackages(JavaType element) {
		ArrayList<String> ret = new ArrayList<String>();
		String pathname = element.getPackage().getName();
		String packages = element.getPackage().getName();
		JavaPackage pack = element.getPackage();
		while (pack.getNestingPackage() != null) {
			packages = pack.getNestingPackage().getName() + "." + packages;
			pathname = pack.getNestingPackage().getName() + "/" + pathname;
			pack = pack.getNestingPackage();
		}
		ret.add(packages);
		ret.add(pathname);
		return ret;
	}

}
